package com.code.generator.context.velocity;


import com.code.generator.context.GeneratorContext;
import com.code.exception.CodeGenerateException;
import com.code.entity.GenerateDescriptor;
import com.code.entity.metadata.Table;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class VelocityGeneratorContext extends VelocityContext implements GeneratorContext {

    private static final Pattern PATTERN_CAMEL_IDENTIFY = Pattern.compile("[_|\\-]([a-z])");

    static {
        Velocity.setProperty("file.resource.loader.class",
                "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init();
    }

    private String prefix = "t_";

    private final GenerateDescriptor descriptor;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public VelocityGeneratorContext(GenerateDescriptor descriptor) {
        this.descriptor = descriptor;
        initialize();
    }

    public VelocityGeneratorContext(GenerateDescriptor descriptor, String tablePrefix) {
        this.prefix = tablePrefix;
        this.descriptor = descriptor;
        initialize();
    }

    private void initialize() {
        Table table = descriptor.getTable();
        if (table == null) {
            throw new CodeGenerateException("数据库表不能为 null !");
        }

        put("table", table);
        String tableName = table.getName().toLowerCase();
        if (tableName.indexOf(this.prefix) == 0) {
            int prefixLength = this.prefix.length();
            tableName = tableName.substring(prefixLength);
        }
        Matcher matcher = PATTERN_CAMEL_IDENTIFY.matcher(tableName);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(buffer, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(buffer);
        String name = buffer.toString();

        put("name", name);
        char[] chars = name.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] -= 32;
        }
        String entity = new String(chars);
        put("useProvider", descriptor.isUseProvider());
        put("entity", entity);
        put("module", descriptor.getModule());
        chars = descriptor.getModule().toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] -= 32;
        }
        put("Module", new String(chars));
        put("packagePersistence", String.join(".", descriptor.getBasePackage(), "entity.persistence"));
        put("packageFilter", String.join(".", descriptor.getBasePackage(), "entity.filter"));
        put("packageFacade", String.join(".", descriptor.getBasePackage(), "entity.facade"));
        put("packageMapper", String.join(".", descriptor.getBasePackage(), "repository.mapper"));
        put("packageRepository", String.join(".", descriptor.getBasePackage(), "repository"));
        put("packageRepositoryImpl", String.join(".", descriptor.getBasePackage(), "repository.impl"));
        put("packageServiceImpl", String.join(".", descriptor.getBasePackage(), "service.impl"));
        put("packageController", String.join(".", descriptor.getBasePackage(), "controller"));
        put("packageModel", String.join(".", descriptor.getBasePackage(), "entity.model"));
        put("packageService", String.join(".", descriptor.getBasePackage(), "service"));
        put("packageRequest", String.join(".", descriptor.getBasePackage(), "request." + name.toLowerCase()));
        put("commonPackage", descriptor.getCommonPackage());
        put("xmlFileterPath", String.join(".", descriptor.getBasePackage(), "repository.mapper.ProjectCommonMapper.filter"));
        put("xmlFileterOrderPath", String.join(".", descriptor.getBasePackage(), "repository.mapper.ProjectCommonMapper.orderBy"));
    }

    @Override
    public String destination() {
        return descriptor.getDestination();
    }

    private String buildPackage(String basePackage, String module, String subPackage) {
        return basePackage + "." + module + "." + subPackage;
    }
}
